/*
 * ParseGPX.cpp
 *
 *  Created on: Jan 26, 2010
 *      Author: rolson
 */

#include "ParseGPX.h"

ParseGPX::ParseGPX(string gpxFilename, WaypointDB& theDB) :
	parser(0), dbToSaveTo(theDB), errHandler(0)
{
	this->gpxFilename = gpxFilename;

	if (dbToSaveTo.initializeDB(this->gpxFilename) == false)
	{
		cout << "Couldn't initialize the database" << endl;
		throw ;
	}

	try
	{
		// First we need to initialize the library
		XMLPlatformUtils::Initialize();

		// Now set up our parser
		parser = new XercesDOMParser();
		parser->setValidationScheme(XercesDOMParser::Val_Always);

		// And the error handler
		errHandler = (ErrorHandler*) new HandlerBase();
		parser->setErrorHandler(errHandler);

	}
	catch (const XMLException& toCatch)
	{
		cout << "Could not initialize Xerces!" << endl;
		throw;
	}

	// Now try to load the file into the DOM...
	if (loadGPXFile() == false)
	{
		cout << "Could not load the file into the DOM, so we're not going to continue" << endl;
		return;
	}

	// Okay, so now we can start loading the data
	loadWaypointsIntoDB();
}

ParseGPX::~ParseGPX()
{
	delete parser;
	delete errHandler;

	XMLPlatformUtils::Terminate();
}

bool ParseGPX::loadGPXFile(void)
{
	try
	{
		parser->parse(this->gpxFilename.c_str());
	}
	catch (const XMLException& toCatch)
	{
		char* message = XMLString::transcode(toCatch.getMessage());
		cout << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
		return false;
	}
	catch (const DOMException& toCatch)
	{
		char* message = XMLString::transcode(toCatch.msg);
		cout << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
		return false;
	}
	catch (...)
	{
		cout << "Unexpected Exception \n";
		return false;
	}

	return true;
}

void ParseGPX::loadWaypointsIntoDB()
{
	try
	{
		cout << "Trying..." << endl;

		DOMDocument* xmlDoc = parser->getDocument();

		DOMElement* elementRoot = xmlDoc->getDocumentElement();

		if (!elementRoot)
			throw(std::runtime_error("empty XML document"));

		DOMNodeList* children = elementRoot->getChildNodes();
		const XMLSize_t nodeCount = children->getLength();

		XMLCh* TAG_Waypoint = XMLString::transcode("wpt");
		XMLCh* ATTR_Lat = XMLString::transcode("lat");
		XMLCh* ATTR_Long = XMLString::transcode("lon");
		XMLCh* TAG_Name = XMLString::transcode("name");
		XMLCh* TAG_Desc = XMLString::transcode("desc");

		// For all nodes, children of "gpx" in the XML tree.
		for (XMLSize_t xx = 0; xx < nodeCount; ++xx)
		{
			string descriptionData, nameData, latitudeData, longitudeData;

			DOMNode* currentNode = children->item(xx);
			if (currentNode->getNodeType() && // true is not NULL
					currentNode->getNodeType() == DOMNode::ELEMENT_NODE) // is element
			{
				// Found node which is an Element. Re-cast node as element
				DOMElement* currentElement = dynamic_cast<xercesc::DOMElement*> (currentNode);

				if (XMLString::equals(currentElement->getTagName(), TAG_Waypoint))
				{
					// Okay, first we have to get the latitude and longitude for this waypoint, which are stored as attributes
					// to the wpt tag
					const XMLCh* xmlch_OptionA = currentElement->getAttribute(ATTR_Lat);
					latitudeData = XMLString::transcode(xmlch_OptionA);
					const XMLCh* xmlch_OptionB = currentElement->getAttribute(ATTR_Long);
					longitudeData = XMLString::transcode(xmlch_OptionB);

					// Now we want to get name tag
					DOMNodeList* wptChildren = currentElement->getChildNodes();
					for (XMLSize_t childxx = 0; childxx < wptChildren->getLength(); ++childxx)
					{
						DOMNode* currentChildNode = wptChildren->item(childxx);

						// Get the name tag
						if (currentChildNode->getNodeType() && // true is not NULL
								currentChildNode->getNodeType() == DOMNode::ELEMENT_NODE) // is element
						{
							// Found node which is an Element. Re-cast node as element
							DOMElement * currentChildElement =
									dynamic_cast<xercesc::DOMElement*> (currentChildNode);
							if (XMLString::equals(currentChildElement->getTagName(), TAG_Name))
							{
								nameData
										= XMLString::transcode(currentChildElement->getTextContent());
							}
						}

						// Get the description
						if (currentChildNode->getNodeType() && // true is not NULL
								currentChildNode->getNodeType() == DOMNode::ELEMENT_NODE) // is element
						{
							// Found node which is an Element. Re-cast node as element
							DOMElement * currentChildElement =
									dynamic_cast<xercesc::DOMElement*> (currentChildNode);
							if (XMLString::equals(currentChildElement->getTagName(), TAG_Desc))
							{
								descriptionData
										= XMLString::transcode(currentChildElement->getTextContent());
							}
						}
					}
				}
			}

			// Now we need to add the data to the database
			addDataToDB(nameData, descriptionData, latitudeData, longitudeData);
		}

		XMLString::release(&TAG_Waypoint);
		XMLString::release(&ATTR_Lat);
		XMLString::release(&ATTR_Long);
		XMLString::release(&TAG_Name);
		XMLString::release(&TAG_Desc);
	}
	catch (xercesc::XMLException& e)
	{
		char* message = xercesc::XMLString::transcode(e.getMessage());

		std::ostringstream errBuf;

		errBuf << "Error parsing file: " << message << std::flush;

		XMLString::release(&message);
	}
}

void ParseGPX::addDataToDB(	const string& name,
							const string& description,
							const string& latitude,
							const string& longitude)
{
	if (name.size() > 0 && description.size() > 0 && latitude.size() > 0 && longitude.size() > 0)
	{
		Waypoint wp(name, description, latitude, longitude);
		dbToSaveTo.addRow(wp);
	}
}
